package be.ipl.uccimpl;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;

import javax.ejb.EJB;
import javax.ejb.Lock;
import javax.ejb.LockType;
import javax.ejb.Singleton;
import javax.ejb.Startup;

import be.ipl.dao.CaseDao;
import be.ipl.dao.JoueurDao;
import be.ipl.dao.PartieDao;
import be.ipl.dao.TableauDao;
import be.ipl.domaine.Jeton;
import be.ipl.domaine.Joueur;
import be.ipl.domaine.Partie;
import be.ipl.domaine.Partie.Etat;
import be.ipl.domaine.Tableau;
import be.ipl.exception.ArgumentInvalideException;
import be.ipl.ucc.GestionParties;
import be.ipl.util.Util;

/**
 * The Class GestionPartiesImpl.
 */
@Singleton
@Startup
public class GestionPartiesImpl implements GestionParties {

	/** The partie dao. */
	@EJB
	PartieDao partieDao;

	/** The tableau dao. */
	@EJB
	TableauDao tableauDao;

	/** The case dao. */
	@EJB
	CaseDao caseDao;

	/** The joueur dao. */
	@EJB
	private JoueurDao joueurDao;

	/** The liste parties suspendues. */
	private Map<Integer, AtomicInteger> listePartiesSuspendues = new HashMap<Integer, AtomicInteger>();

	/** The de value. */
	private int nbrGetDe;

	/** The partie. */
	private Partie partie;
	private int toutLeMondeADeplace = 0;

	@Override
	public List<Partie> listerPartiesARejoindre() {
		return partieDao.listerPartiesARejoindre();
	}

	@Override
	public List<Partie> listerPartiesAReprendre(String login) {
		return partieDao.listerPartiesAReprendre(login);
	}

	@Override
	public Partie rechercherPartie(int idPartie) {
		try {
			Util.checkPositive(idPartie);
		} catch (ArgumentInvalideException e) {
			e.printStackTrace();
		}
		return partieDao.rechercher(idPartie);
	}

	@Override
	public Partie chargerTout(Partie partie) {
		try {
			Util.checkObject(partie);
		} catch (ArgumentInvalideException e) {
			e.printStackTrace();
		}
		if (partie.getId_partie() == 0)
			return partie;
		partie = partieDao.chargerJetonsEtTableaux(partie);
		for (Tableau tab : partie.getTableaux()) {
			tab = tableauDao.chargerTableaux(tab);
		}
		return partie;
	}

	@Override
	public Partie creerPartie(String nomPartie, String login) {
		try {
			Util.checkString(nomPartie);
			Util.checkString(login);
		} catch (ArgumentInvalideException e) {
			e.printStackTrace();
		}

		Joueur joueur = joueurDao.rechercher(login);
		Partie laPartie = new Partie(nomPartie, joueur);
		this.partie = partieDao.enregistrer(laPartie);
		return this.partie;
	}

	public boolean rejoindrePartie(int idPartie, String login) {
		try {
			Util.checkPositive(idPartie);
			Util.checkString(login);
		} catch (ArgumentInvalideException e) {
			e.printStackTrace();
		}
		partie = partieDao.recharger(idPartie);
		if (partie.getEtat() != Etat.EN_ATTENTE)
			return false;
		Joueur joueur = joueurDao.rechercher(login);
		boolean result = partie.ajouterJoueur(joueur);
		this.partie = partieDao.enregistrer(partie);
		return result;
	}

	@Override
	public boolean commencerPartie(int idPartie) {
		try {
			Util.checkPositive(idPartie);
		} catch (ArgumentInvalideException e) {
			e.printStackTrace();
		}
		partie = partieDao.recharger(idPartie);
		boolean result = partie.commencerPartie();
		if (result)
			this.partie = partieDao.mettreAJour(partie);
		return result;
	}

	@Override
	@Lock(LockType.READ)
	public boolean partieEstEnCours(int idPartie) {
		try {
			Util.checkPositive(idPartie);
		} catch (ArgumentInvalideException e) {
			e.printStackTrace();
		}
		partie = partieDao.rechercher(idPartie);
		boolean result = partie.partieEstEnCours();
		return result;
	}

	public boolean toutLeMondeADeplace(int idPartie) {
		try {
			Util.checkPositive(idPartie);
		} catch (ArgumentInvalideException e) {
			e.printStackTrace();
		}
		toutLeMondeADeplace++;
		if ((toutLeMondeADeplace % partie.getNbJoueurs()) == 0)
			return true;
		return false;
	}

	@Override
	public boolean suspendrePartie(int idPartie) {
		try {
			Util.checkPositive(idPartie);
		} catch (ArgumentInvalideException e) {
			e.printStackTrace();
		}
		partie = partieDao.recharger(idPartie);
		if (partieEstEnCours(partie.getId_partie())) {
			partie.setNbJoueurs(nombreJoueurPartie(partie.getId_partie()));
			listePartiesSuspendues.put(partie.getId_partie(),
					new AtomicInteger(partie.getNbJoueurs()));
			partie.suspendrePartie();
			partieDao.mettreAJour(partie);
			return true;
		}
		return false;
	}

	@Override
	public boolean cloturerPartie(int idPartie) {
		try {
			Util.checkPositive(idPartie);
		} catch (ArgumentInvalideException e) {
			e.printStackTrace();
		}
		partie = partieDao.recharger(idPartie);
		if (partie.cloturerPartie()) {
			partieDao.enregistrer(partie);
			return true;
		}
		return false;
	}

	@Override
	public Map<String, String> obtenirScore(int idPartie) {
		try {
			Util.checkPositive(idPartie);
		} catch (ArgumentInvalideException e) {
			e.printStackTrace();
		}
		partie = partieDao.recharger(idPartie);
		return partie.classement();
	}

	@Override
	public boolean reprendrePartie(int idPartie, String login) {
		try {
			Util.checkPositive(idPartie);
			Util.checkString(login);
		} catch (ArgumentInvalideException e) {
			e.printStackTrace();
		}
		partie = partieDao.recharger(idPartie);

		if (!partie.verifierJoueurPartie(login)) {
			return false;
		}

		AtomicInteger nbJoueursSuspendue;
		if (partie.getEtat() == Etat.SUSPENDUE) {

			nbJoueursSuspendue = listePartiesSuspendues.get(partie
					.getId_partie());
			if (nbJoueursSuspendue != null) {

				if (nbJoueursSuspendue.get() == 1) {
					listePartiesSuspendues.remove(partie.getId_partie());
					return partie.reprendreUnePartie();
				} else {
					nbJoueursSuspendue.decrementAndGet();
					listePartiesSuspendues.put(partie.getId_partie(),
							nbJoueursSuspendue);
					return true;
				}
			}

		}
		return false;
	}

	@Override
	public List<Jeton> donnerTroisJetons(int idPartie) {
		try {
			Util.checkPositive(idPartie);
		} catch (ArgumentInvalideException e) {
			e.printStackTrace();
		}
		partie = partieDao.rechercher(idPartie);
		partie = chargerTout(partie);
		List<Jeton> tmp = new ArrayList<Jeton>();
		tmp = partie.distribuerTroisJetons();
		partie = partieDao.mettreAJour(partie);
		return tmp;
	}

	@Override
	public void supprimerPartie(int idPartie) {
		try {
			Util.checkPositive(idPartie);
		} catch (ArgumentInvalideException e) {
			e.printStackTrace();
		}
		partie = partieDao.recharger(idPartie);
		partieDao.supprimer(partie.getId_partie());
	}

	public int nombreJoueurPartie(int idPartie) {
		try {
			Util.checkPositive(idPartie);
		} catch (ArgumentInvalideException e) {
			e.printStackTrace();
		}
		partie = partieDao.recharger(idPartie);
		return partie.getTableaux().size();

	}

	@Override
	public int getDe(int idPartie) {
		try {
			Util.checkPositive(idPartie);
		} catch (ArgumentInvalideException e) {
			e.printStackTrace();
		}
		partie = partieDao.rechercher(idPartie);
		partie = chargerTout(partie);
		int de = partie.getDe();
		nbrGetDe++;
		System.out.println("getDe cbn de fois : " + nbrGetDe);
		if ((nbrGetDe % partie.getNbJoueurs()) == 0)
			partie.lancerDe();
		partie = partieDao.mettreAJour(partie);
		return de;
	}

	@Override
	public boolean tousJoueursOntPlace(int partieId) {
		try {
			Util.checkPositive(partieId);
		} catch (ArgumentInvalideException e) {
			e.printStackTrace();
		}
		partie = partieDao.rechercher(partieId);
		partie = chargerTout(partie);
		int nbrCaseOccParJoueur = caseDao.listerCase(
				partie.getTableaux().get(0)).size();
		int tmp = 0;
		for (Tableau tab : partie.getTableaux()) {
			tmp = caseDao.listerCase(tab).size();
			if (tmp != nbrCaseOccParJoueur)
				return false;
		}
		return true;
	}

	@Override
	public boolean unGagnant(int partieId) {
		try {
			Util.checkPositive(partieId);
		} catch (ArgumentInvalideException e) {
			e.printStackTrace();
		}
		partie = partieDao.rechercher(partieId);
		partie = chargerTout(partie);
		return partie.detecterVainqueur();
	}

}
